package org.wltea.analyzer.lucene;

import java.io.IOException;
import java.io.Reader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.core.LowerCaseFilter;
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
import org.apache.lucene.analysis.synonym.SolrSynonymParser;
import org.apache.lucene.analysis.synonym.SynonymFilter;
import org.apache.lucene.analysis.synonym.SynonymMap;
import org.apache.lucene.analysis.util.ResourceLoader;
import org.apache.lucene.analysis.util.ResourceLoaderAware;
import org.apache.lucene.analysis.util.TokenFilterFactory;
import org.apache.lucene.util.CharsRef;
import org.apache.lucene.util.Version;

import com.hunteron.jdbc.bean.SameWord;
import com.hunteron.jdbc.dao.SameWordDao;
import com.hunteron.util.PropertieUtil;

public class IKSynonymFilterFactory extends TokenFilterFactory implements ResourceLoaderAware {

    public IKSynonymFilterFactory(Map<String, String> args) throws IOException {
        super(args);

        expand = getBoolean(args, "expand", true);
        // synonyms = get(args, "synonyms");
        ignoreCase = getBoolean(args, "ignoreCase", false);
        isAutoUpdate = getBoolean(args, "autoupdate", false);
        isAutoUpdate = false;
    }

    // private String synonyms;
    private static SynonymMap map;
    private boolean ignoreCase;
    private boolean expand;

    boolean isAutoUpdate;

    Analyzer analyzer = null; // 包访问权限，共用？

    private static Boolean isUpdateStart = false;

    private long RELOAD_SECONDS = PropertieUtil.getLongProp("resource", "synReloadSeconds");

    public void inform(ResourceLoader loader) throws IOException {

        // IKAnalyzer analyzer = new IKAnalyzer(); // max words
        final Analyzer analyzer = new Analyzer() {
            @Override
            protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
                WhitespaceTokenizer tokenizer = new WhitespaceTokenizer(Version.LUCENE_47, reader);
                @SuppressWarnings("resource")
                TokenStream stream = ignoreCase ? new LowerCaseFilter(Version.LUCENE_47, tokenizer) : tokenizer;
                return new TokenStreamComponents(tokenizer, stream);
            }
        };

        this.analyzer = analyzer;

        try {
            map = loadSolrSynonyms(true, analyzer);
            synchronized (isUpdateStart) {
                if (!isUpdateStart) {
                    isUpdateStart = true;

                    ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
                    executor.scheduleWithFixedDelay(new Runnable() {
                        public void run() {
                            try {
                                map = loadSolrSynonyms(true, analyzer);
                            } catch (IOException e) {
                                e.printStackTrace();
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
                        }
                    }, RELOAD_SECONDS, RELOAD_SECONDS, TimeUnit.SECONDS);
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
            throw new IOException("Exception thrown while loading synonyms", e);
        }

    }

    /**
     * 加载同义词词典
     * 
     * @param loader
     * @param dedup
     * @param analyzer
     * @return
     * @throws IOException
     * @throws ParseException
     */
    private SynonymMap loadSolrSynonyms(boolean dedup, Analyzer analyzer) throws IOException, ParseException {

        // 不需要同义词词典，直接数据库加载
        SolrSynonymParser parser = new SolrSynonymParser(dedup, expand, analyzer);

        if (isUpdateStart) {
            // 动态数据库加载
            SameWordDao sameWordDao = new SameWordDao();
            while (sameWordDao.hasNext()) {
                List<SameWord> words = sameWordDao.more();
                if (words != null && words.size() > 0) {
                    for (SameWord w : words) {
                        addSynWord(parser, w.getKeyword());
                    }
                }
            }
        }

        return parser.build();
    }

    @Override
    public TokenStream create(TokenStream input) {
        if (map.fst == null) {
            return input;
        } else {
            return new SynonymFilter(input, map, ignoreCase);
        }
    }

    public static Boolean isUpdate = false;

    private void addSynWord(SolrSynonymParser parser, String[] list) throws IOException {
        if (list == null || list.length < 2) {
            return;
        }

        List<CharsRef> left = new ArrayList<CharsRef>();
        List<CharsRef> right = new ArrayList<CharsRef>();

        for (String w : list) {
            if (StringUtils.isBlank(w) || w.length() < 1) {
                continue;
            }
            if (w.indexOf("_") > 0 || w.split("_").length > 1) {
                w = w.toLowerCase();
                List<CharsRef> temp = getCharsRef(w);
                if (temp != null) {
                    right.addAll(temp);
                }
            } else {
                w = w.toLowerCase();
                // CharsRef temp = SynonymMap.Builder.analyze(analyzer, unescape(w).trim(), new CharsRef());
                CharsRef temp = new CharsRef(unescape(w).trim());
                left.add(temp);
                right.add(temp);
            }

        }

        for (CharsRef l : left) {
            for (CharsRef r : right) {
                parser.add(l, r, false);
            }
        }
    }

    private List<CharsRef> getCharsRef(String word) {
        List<CharsRef> rs = new ArrayList<CharsRef>();
        String[] wds = word.split("_");
        for (int i = 0; i < wds.length; i++) {
            String w = wds[i];
            if (w == null || w.length() < 1) {
                continue;
            }
            // rs.add(SynonymMap.Builder.analyze(analyzer, unescape(w).trim(), new CharsRef()));
            rs.add(new CharsRef(w.trim()));
        }
        return rs;
    }

    private String unescape(String s) {
        if (s.indexOf("\\") >= 0) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.length(); i++) {
                char ch = s.charAt(i);
                if (ch == '\\' && i < s.length() - 1) {
                    sb.append(s.charAt(++i));
                } else {
                    sb.append(ch);
                }
            }
            return sb.toString();
        }
        return s;
    }

    public static void main(String[] args) {
        System.out.println("aa+bb".indexOf("+"));
    }
}
